﻿using System;
using System.IO.IsolatedStorage;
using System.Linq.Expressions;
using System.Reflection;

namespace BluEtch.GotPhone.Data
{
    public class IsolatedDataBase
    {
        // Isolated storage settings for the current application
        IsolatedStorageSettings _settings;

        /// <summary>
        /// Setting this to true will call Save() automatically every time a property is set.
        /// </summary>
        protected bool AutoSave { get; set; }

        public IsolatedDataBase()
        {
            // Get the settings for this application
            _settings = IsolatedStorageSettings.ApplicationSettings;

            AutoSave = false;
        }

        /// <summary>
        /// Add or update a stored value for this application. Allows strongly-typed property
        /// assignment in the form of the following.
        ///     set { SetValue(() => this.MyProperty, value); }
        /// </summary>
        /// <typeparam name="TValue">Type of object</typeparam>
        /// <param name="propertyExpression"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        protected bool SetValue<TValue>(Expression<Func<TValue>> propertyExpression, object value)
        {
            var property = Helpers.Internal.GetPropertyInfoFromExpression(propertyExpression);

            bool updated = false;

            // Check key exists
            if (IsSettingPersisted(property.Name))
            {
                // If value changed
                if (!Equals(_settings[property.Name], value))
                {
                    // Update value
                    _settings[property.Name] = value;
                    updated = true;
                }
            }
            else
            {
                // Create the key
                _settings.Add(property.Name, value);
                updated = true;
            }

            if (updated == true && AutoSave)
            {
                Save();
            }

            return updated;
        }

        /// <summary>
        /// Get stored value or default value. Allows strongly-typed property value retrieval
        /// in the form of the following. Allows you to specify a default value.
        ///     get { return GetValue(() => this.MyProperty); }
        /// </summary>
        /// <typeparam name="T">Type of value to be retrieved</typeparam>
        /// <param name="valueSelector">Expression to retrieve name of property</param>
        /// <param name="defaultValue">Type of default value</param>
        /// <returns></returns>
        protected T GetValue<T>(Expression<Func<T>> valueSelector, T defaultValue = default(T))
        {
            var property = Helpers.Internal.GetPropertyInfoFromExpression(valueSelector);

            T value;

            // If the key exists, retrieve the value. Otherwise, retrieve default value.
            if (IsSettingPersisted(property.Name))
            {
                value = (T)_settings[property.Name];
            }
            else
            {
                value = defaultValue;
            }

            return value;
        }

        /// <summary>
        /// Checks to see if a setting is persisted in application settings based on a key name.
        /// </summary>
        /// <param name="key">string name of a key</param>
        /// <returns>true if setting is persisted</returns>
        protected bool IsSettingPersisted(string key)
        {
            return (_settings != null && _settings.Contains(key));
        }

        /// <summary>
        /// Checks to see if a setting is persisted in application settings based on a key name
        /// derived from an expression. In the form of:
        ///     IsSettingPersisted(() => this.MyProperty);
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="valueSelector"></param>
        /// <returns></returns>
        protected bool IsSettingPersisted<T>(Expression<Func<T>> valueSelector)
        {
            var property = Helpers.Internal.GetPropertyInfoFromExpression(valueSelector);

            return (_settings != null && _settings.Contains(property.Name));
        }

        public void Save()
        {
            _settings.Save();
        }
    }
}
